package com.mchina.myMaven.rest.dao.hibernate;


import com.mchina.myMaven.rest.dao.BaseDao;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.*;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Example.PropertySelector;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.transform.Transformers;
import org.hibernate.type.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;


/**
 * DAO基类。
 * <p/>
 * 提供hql分页查询，example分页查询，拷贝更新等功能。
 *
 * @param <T>
 */
@Repository
public abstract class BaseDaoImpl<T extends Serializable> implements BaseDao<T> {
    protected Logger log = LoggerFactory.getLogger(getClass());

    protected SessionFactory sessionFactory;

    @Autowired
    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    protected Session getSession() {
        return sessionFactory.getCurrentSession();
    }


    public T save(T entity) {
        Assert.notNull(entity);
        getSession().save(entity);
        if (1 == 1) {
            // throw new Exception("事务");
        }
        return entity;
    }

    public Object update(Object entity) {
        Assert.notNull(entity);
        getSession().update(entity);
        return entity;
    }

    public Object saveOrUpdate(Object entity) {
        Assert.notNull(entity);
        getSession().saveOrUpdate(entity);
        return entity;
    }

    public Object merge(Object entity) {
        Assert.notNull(entity);
        return getSession().merge(entity);
    }

    public void delete(Object entity) {
        Assert.notNull(entity);
        getSession().delete(entity);
    }

    public T deleteById(Serializable id) {
        Assert.notNull(id);
        T entity = load(id);
        getSession().delete(entity);

        return entity;
    }

    public T load(Serializable id) {
        Assert.notNull(id);
        return load(id, false);
    }

    @SuppressWarnings("unchecked")
    public T get(Serializable id) {
        Assert.notNull(id);
        return (T) getSession().get(getPersistentClass(), id);
    }

    @SuppressWarnings("unchecked")
    public T load(Serializable id, boolean lock) {
        Assert.notNull(id);
        T entity = null;
        if (lock) {
            entity = (T) getSession().load(getPersistentClass(), id,
                    LockMode.UPGRADE);
        } else {
            entity = (T) getSession().load(getPersistentClass(), id);
        }
        return entity;
    }

    public List<T> findAll() {
        return findByCriteria();
    }


    /**
     * 按HQL查询对象列表.
     *
     * @param hql    hql语句
     * @param values 数量可变的参数
     */
    @SuppressWarnings("unchecked")
    public List find(String hql, Object... values) {
        return createQuery(hql, values).list();
    }

    public List findBySql(String sql) {

        SQLQuery sqlQuery = getSession().createSQLQuery(sql);
        //sqlQuery.g
        //finder.setParamsToQuery(sqlQuery);
        Query query = sqlQuery.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP); //返回一个map,KEY
        List l = query.list();

        return l;
    }

    /**
     * 按HQL查询唯一对象.
     */
    protected Object findUnique(String hql, Object... values) {
        return createQuery(hql, values).uniqueResult();
    }

    /**
     * 按属性查找对象列表.
     */
    @SuppressWarnings("unchecked")
    public List<T> findByProperty(String property, Object value) {
        Assert.hasText(property);
        return createCriteria(Restrictions.eq(property, value)).list();
    }

    /**
     * 按属性查找唯一对象.
     */
    @SuppressWarnings("unchecked")
    public T findUniqueByProperty(String property, Object value) {
        Assert.hasText(property);
        Assert.notNull(value);
        return (T) createCriteria(Restrictions.eq(property, value))
                .uniqueResult();
    }

    public int countByProperty(String[] property, Object[] value) {
        Criteria c = createCriteria();
        for (int i = 0; i < property.length; i++) {
            Assert.hasText(property[i]);
            Assert.notNull(value[i]);

            c.add(Restrictions.eq(property[i], value[i]));

        }
        return ((Number) c.setProjection(Projections.rowCount()).uniqueResult()).intValue();
    }

    public int countByProperty(String property, Object value) {
        Assert.hasText(property);
        Assert.notNull(value);
        return ((Number) (createCriteria(Restrictions.eq(property, value))
                .setProjection(Projections.rowCount()).uniqueResult()))
                .intValue();
    }


    /**
     * 根据查询函数与参数列表创建Query对象,后续可进行更多处理,辅助函数.
     */
    protected Query createQuery(String queryString, Object... values) {
        Assert.hasText(queryString);
        Query queryObject = getSession().createQuery(queryString);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                queryObject.setParameter(i, values[i]);
            }
        }
        return queryObject;
    }

    /**
     * 按Criterion查询对象列表.
     *
     * @param criterion 数量可变的Criterion.
     */
    @SuppressWarnings("unchecked")
    protected List<T> findByCriteria(Criterion... criterion) {
        return createCriteria(criterion).list();
    }


    /**
     * 通过sql查询获得本次查询所能获得的对象总数.
     *
     * @param sql
     * @return
     */

    public int countQueryResult(String sql) {
        SQLQuery sqlQuery = getSession().createSQLQuery(sql);
        return ((Number) sqlQuery.uniqueResult()).intValue();
    }


    public void refresh(Object entity) {
        getSession().refresh(entity);
    }


    /**
     * 根据Criterion条件创建Criteria,后续可进行更多处理,辅助函数.
     */
    protected Criteria createCriteria(Criterion... criterions) {
        Criteria criteria = getSession().createCriteria(getPersistentClass());
        for (Criterion c : criterions) {
            criteria.add(c);
        }
        return criteria;
    }

    private Class<T> persistentClass;

    @SuppressWarnings("unchecked")
    public BaseDaoImpl() {
        this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
                .getGenericSuperclass()).getActualTypeArguments()[0];
    }

    public Class<T> getPersistentClass() {
        return persistentClass;
    }

    public T createNewEntiey() {
        try {
            return getPersistentClass().newInstance();
        } catch (Exception e) {
            throw new RuntimeException("不能创建实体对象："
                    + getPersistentClass().getName());
        }
    }

    @SuppressWarnings("unchecked")
    private ClassMetadata getCmd(Class clazz) {
        return (ClassMetadata) sessionFactory.getClassMetadata(clazz);
    }

    public static final NotBlankPropertySelector NOT_BLANK = new NotBlankPropertySelector();

    /**
     * 不为空的EXAMPLE属性选择方式
     *
     * @author liufang
     */
    static final class NotBlankPropertySelector implements PropertySelector {
        private static final long serialVersionUID = 1L;

        public boolean include(Object object, String property, Type type) {
            return object != null
                    && !(object instanceof String && StringUtils
                    .isBlank((String) object));
        }
    }


}
